# Styling

> Supacharger uses Tailwind CSS as its styling foundation. The root layout imports one CSS entrypoint:

# Styling

Supacharger uses Tailwind CSS as its styling foundation. The root layout imports one CSS entrypoint:

```ts
import '@/supacharger/styles/globals.css';
```

That entrypoint loads Tailwind, the shared Supacharger styles, the developer-owned authentication presentation, and the application's general developer-owned stylesheet in that order. Do not import them again from the layout.

## Style ownership

| File | Owner | Purpose |
| --- | --- | --- |
| `src/supacharger/styles/globals.css` | Supacharger CLI | Tailwind entrypoint and import order only |
| `src/supacharger/styles/supacharger.css` | Supacharger CLI | Reusable Supacharger element and component rules |
| `src/supacharger/styles/project.example.css` | Supacharger CLI | Unimported reference for the developer stylesheet |
| `src/styles/supacharger-auth.css` | Application developer | Presentation for managed authentication `sc-auth-*` hooks |
| `src/styles/project.css` | Application developer | Project theme tokens, global defaults, overrides, and product-specific classes |

The CLI may replace files under `src/supacharger/styles/` during a core update. It installs `src/styles/supacharger-auth.css` when absent, then preserves it alongside `src/styles/project.css` and `src/supacharger.config.ts`.

Keep the `Project: ...` header in `project.css` updated with the application name. This makes the ownership of copied or compared styles explicit.

## Tailwind conventions

Use Tailwind utilities in markup for most styling. Add CSS only when a reusable semantic rule, an element default, a theme token, or a project-wide override is genuinely clearer than repeated utilities.

Place custom CSS in Tailwind's layers:

- `@layer base` for project theme variables and element defaults;
- `@layer components` for reusable semantic component classes; and
- `@layer utilities` for small, single-purpose project utilities.

Tailwind's Preflight already supplies the normal reset through `@import 'tailwindcss'`. Do not reproduce Preflight rules in project CSS, and do not add another Tailwind import to `project.css`.

The merge-managed `tailwind.config.ts` retains its TypeScript filename, application font choices, and current CommonJS export. The exact-managed `postcss.config.mjs` uses an explicit ESM export so Next.js and Turbopack can evaluate the Tailwind PostCSS plugin reliably. Keep the `@config` reference unchanged and do not add a package-wide `"type": "module"` solely for either file.

## Shared Supacharger rules

Rules that every Supacharger application should receive belong in the CLI-managed core stylesheet. Supacharger centrally gives enabled native and ARIA interactive controls a pointer cursor on hover:

```css title="src/supacharger/styles/supacharger.css"
@layer base {
  html {
    scroll-behavior: smooth;
  }

  @media (prefers-reduced-motion: reduce) {
    html {
      scroll-behavior: auto;
    }
  }

  :where(
    a[href],
    button:not(:disabled),
    input[type='button']:not(:disabled),
    input[type='submit']:not(:disabled),
    input[type='reset']:not(:disabled),
    input[type='checkbox']:not(:disabled),
    input[type='radio']:not(:disabled),
    label[for],
    select:not(:disabled),
    summary,
    [role='button']:not([aria-disabled='true']),
    [role='link']:not([aria-disabled='true']),
    [role='menuitem']:not([aria-disabled='true']),
    [role='menuitemcheckbox']:not([aria-disabled='true']),
    [role='menuitemradio']:not([aria-disabled='true']),
    [role='option']:not([aria-disabled='true']),
    [role='tab']:not([aria-disabled='true'])
  ) {
    cursor: pointer !important;
  }
}
```

The root rule is the native fallback for same-page fragment links. The installed root layout also mounts `SmoothAnchorNavigation` from `src/supacharger/components/layout/smooth-anchor-navigation.tsx`, because Next.js `<Link>` can otherwise perform an immediate fragment jump before CSS animates it. Together they make `<a href="#features">` and `<Link href="#features">` work automatically. Modified clicks, downloads, non-self targets, and missing fragments retain normal browser behaviour; add `data-smooth-scroll="false"` to opt out for one link. Visitors who request reduced motion receive immediate navigation. The `!important` cursor declaration intentionally keeps that interaction affordance authoritative when a component library supplies `cursor-default`. Disabled controls are excluded so they do not misleadingly advertise an available action. Ordinary components therefore should not repeat `cursor-pointer` or page-level smooth-scroll utilities.

Change this file in the canonical Supacharger core first, then distribute the same file through the CLI. Do not add product branding or application-specific selectors to it.

## Project styles

Put the application's colors, typography defaults, visual effects, and overrides in `src/styles/project.css`:

```css title="src/styles/project.css"
/**
 * Project: Example Application
 *
 * Developer-owned. The Supacharger CLI must preserve this file.
 */

@layer base {
  :root {
    --primary: 174 49% 50%;
    --primary-foreground: 222 47% 11%;
  }
}
```

Tailwind color mappings in `tailwind.config.ts` consume these space-separated HSL channels. For example, `#42bfb1` becomes `174 49% 50%`.

`--primary` is the application's main brand action colour and `--primary-foreground` is the content colour placed on top of it. Prefer semantic utilities such as `bg-primary`, `text-primary-foreground`, `text-foreground`, `text-muted-foreground`, `bg-accent`, and `ring-ring`. They automatically follow the named project's light and dark token values; a shared component should not copy a product hex value.

Application-specific classes may override a shared Supacharger class because `project.css` is imported after `supacharger.css`. Keep overrides intentional and document why the consumer differs from the core.

## Theme selector

The shared `ModeToggle` opens a three-position selector ordered System, Light, and Dark. Use `appearance='marketing'` beside the application-owned locale switcher when both controls appear in marketing navigation or a footer. The marketing appearance gives both triggers the same control height, padding, text size, and small radius. The application-owned root layout must mount a compatible theme provider with system mode enabled so every choice can resolve correctly.

## Responsive SVG components

Keep UI SVGs under the developer-owned `src/` path belonging to their feature or surface, with demo-only artwork under `src/components/sc_demo/`. Import them as React components through SVGR and use `public/` only when an asset genuinely needs a URL.

Every responsive SVG must have a valid `viewBox` so it preserves its aspect ratio. When CSS or Tailwind controls the rendered size, remove `width` and `height` from the root `<svg>`:

```svg
<svg viewBox="0 0 323 46" ...>
```

Size the component at its call site with classes such as `size-*`, `w-*`, `h-*`, or `size-[1em]`, and usually add `shrink-0` beside text. Do not force mismatched dimensions or fix clipping with arbitrary component props. Use `fill='currentColor'` or `stroke='currentColor'` only when the artwork should inherit text colour.

Confirm that SVGR/SVGO preserved the rendered `<svg>` element's `viewBox`, test classes such as `h-8 w-auto` at the intended viewport sizes, and verify that the complete artwork stays within its bounds. Add a regression test that checks responsive SVG assets retain their `viewBox` and omit root-level intrinsic dimensions, then visually verify every affected page in the browser.

## Inline loader branding

The primary application-owned inline loading animation lives at `src/assets/svgr/ui/inline-loader.svg`, with a matching black variant at `src/assets/svgr/ui/inline-loader-dark.svg`. Replace either file with a new SVG of the same name to customise it; Supacharger CLI updates preserve both. The shared loading component uses the primary asset.

This is an inline-loader convention for pending buttons, form actions, uploads, and compact content states. It does not replace an application's route-level or full-page loading design.

Render the asset as an SVGR component rather than with an image tag or public URL:

```tsx
import InlineLoader from '@/assets/svgr/ui/inline-loader.svg';

<InlineLoader
  aria-label='Saving'
  className='size-5'
  fill='currentColor'
  role='status'
/>
```

The primary loader defaults to white and the dark clone defaults to black. Both use their root `fill`, so an SVGR caller can pass a different colour. A replacement may instead hard-code `fill` or `stroke`; in that case the same prop is harmless and the custom artwork keeps its own colours. Keep all UI SVGs under an appropriate developer-owned `src/` path and import them through SVGR. Reserve `public` SVGs for favicon metadata, manifests, external URL contracts, and other cases that genuinely require a URL.

Colocate feature-owned SVGs with the developer-owned feature when that makes its lifecycle clearer. For example, demo-only logos belong under `src/components/sc_demo/assets/` and are imported through SVGR, so deleting the replaceable demo also deletes its artwork.

[SVG Backgrounds animated SVG preloaders](https://www.svgbackgrounds.com/elements/animated-svg-preloaders/) is one source of replacement animations. Check and satisfy the selected asset's current licence and attribution requirements before publishing it.

## Error and not-found pages

`src/app/error/page.tsx`, `src/app/not-found.tsx`, and their presentation under `src/components/error-page/` are application-owned, CLI-preserved surfaces. This lets a product own its support destination, wording, signed-in chrome, and brand treatment without editing a protected Supacharger route.

The starter pattern verifies the current user on the server. A verified user sees the error state inside the normal authenticated header and footer; every other visitor sees only a vertically centred, full-viewport error state. The actions use the semantic project tokens described above. Keep the explicit `/error` route in `PATH_AUTH_GUARD.UNAUTHED_USER.ALLOWED` when `AUTH_ONLY_APP` is enabled, otherwise an authentication failure can be redirected away from the page intended to explain it. The canonical Proxy also lets `/error` bypass profile-onboarding redirects so an authenticated but incomplete account can still see the failure explanation.

Add translated wording under the developer-owned `ErrorPage` namespace. The error-copy resolver reads any available values directly and supplies protected English defaults for an absent namespace or missing field. This compatibility fallback prevents an older preserved catalogue—or a stale development module—from raising `MISSING_MESSAGE` inside the error boundary itself.

## Fonts

Define application fonts with `next/font` in `src/app/layout.tsx` and expose them through a CSS variable:

```ts
import { Space_Grotesk } from 'next/font/google';

const spaceGrotesk = Space_Grotesk({
  variable: '--font-space-grotesk',
  subsets: ['latin'],
});
```

Apply the generated variable to the body class and map it in Tailwind configuration when it should back a font utility. Next.js downloads Google font assets at build time, so the browser does not request them from Google at runtime.

## Favicon customisation

Use [RealFaviconGenerator](https://realfavicongenerator.net/) to create a complete favicon pack from the application's icon. A 300 × 300 px PNG works well as the source image. Configure the browser, mobile, and manifest options on the site, then download and extract the generated pack to a temporary folder.

Give your coding agent the location of the downloaded archive or extracted folder with a prompt like this:

```text
Install the favicon pack from <path-to-downloaded-archive-or-folder> in this project. Inspect the existing favicon and metadata setup, replace the current favicon files and references with the new pack, and keep the implementation consistent with the framework and project structure. Remove obsolete favicon assets that have been replaced. Verify that the relevant metadata, manifest, and icon paths resolve correctly, then delete the temporary downloaded archive or extracted folder. Preserve unrelated files and summarise what changed.
```

Replace the placeholder with the pack's actual location. The pack does not need to be copied into the project first; it can remain in Downloads or another temporary location while the agent installs it.
